package java_option.player.javacv.core;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Vector;

import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;

import java_option.Config;
import java_option.log.Logger;
import java_option.player.javacv.ext.VideoDurationUpdate;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.WritableImage;

/**
 * <pre>
 *     队列
 * 	用于保存 音视频的 Frame
 *     只要有一个队列满200了 就停止继续grabber
 * </pre>
 * 
 * @author java红了 <br/>
 *         2020-9-2720:02:54
 */
public class FrameFIFO {

	private String tag = FrameFIFO.class.getSimpleName();

	private Vector<FrameWrapper> audioList = new Vector<>();
	private Vector<FrameWrapper> videoList = new Vector<>();
	private Java2DFrameConverter converter = new Java2DFrameConverter();

	private static FrameFIFO instance;

	private FrameFIFO() {

	}

	public static FrameFIFO getInstance() {
		synchronized (FrameFIFO.class) {
			if (instance == null) {
				instance = new FrameFIFO();
			}
		}
		return instance;
	}

	/**
	 * 
	 * @param timeMillis
	 * @param videoFrame
	 * @param audioFrame
	 * @return false 返回false 就是告诉 FrameGrabberThread 不要继续解析Frame了
	 */
	public boolean putVideo(Frame videoFrame, long index) {
		// 视频
		FrameWrapper video = new FrameWrapper();
		video.index = index;
		video.frame = videoFrame.clone();

		BufferedImage bufferedImage = null;
//			bufferedImage = converter.getBufferedImage(videoFrame, //
//					Java2DFrameConverter.getBufferedImageType(videoFrame) == BufferedImage.TYPE_CUSTOM ? 1.0 : 0.45454545454545453, //
//					false, null);
		bufferedImage = converter.getBufferedImage(videoFrame);

		// 缩放到1280x720 - 性能很低 不考虑这种方案
//		BufferedImage after = new BufferedImage(1280, 720, BufferedImage.TYPE_INT_ARGB);
//		AffineTransform at = new AffineTransform();
//		at.scale(1280.0 / 1980, 720.0 / 1080);
//		AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
//		after = getAffineTransformOp().filter(bufferedImage, after);

		BufferedImage after = new BufferedImage(1280, 720, BufferedImage.TYPE_INT_RGB);
		Graphics g = after.createGraphics();
		g.drawImage(bufferedImage, 0, 0, 1280, 720, null);
		g.dispose();

		WritableImage javafxImage = SwingFXUtils.toFXImage(after, null);
		// 释放内存
		bufferedImage.getGraphics().dispose();

		video.javafxImage = javafxImage;
		videoList.add(video);
		// 只要有一个小于Config.MAX_FRAME_SIZE 就继续
		boolean isContinue = videoList.size() < Config.MAX_FRAME_SIZE;
		return isContinue;
	}

	/**
	 * 添加音频
	 * 
	 * @param timeMillis
	 * @param audioFrame
	 * @return
	 */
	public boolean putAudio(Frame audioFrame, long index) {
		Logger.info(tag, "加入音频帧 , 当前一共 " + audioList.size());
		// 音频
		FrameWrapper audio = new FrameWrapper();
		audio.index = index;
		audio.frame = audioFrame.clone();
		audioList.add(audio);

//		System.out.println("加入video 当前一共" + videoList.size());
//		System.out.println("加入audio 当前一共" + audioList.size());

		// 只要有一个小于1000 就继续
		boolean isContinue = audioList.size() < Config.MAX_FRAME_SIZE;
		return isContinue;
	}

	/**
	 * 获取视频Frame 直接返回
	 * 
	 * @return
	 */
	public FrameWrapper readNextVideo() {
		FrameVideoGrabberThread videoGrab = FrameVideoGrabberThread.getInstance();
		if (videoList.isEmpty()) {
			Logger.info(tag, "readNextVideo videoList.isEmpty()");
			if (videoGrab.isGrabEnd() == false) {
				videoGrab.notifyGrab();
			}
			return null;
		} else {
			FrameWrapper wrapper = videoList.get(0);
			videoList.remove(0);// 删除
//			System.out.println("从FrameFIFO中获取一帧video, 剩余 = " + videoList.size());
			if (videoList.size() < Config.MAX_FRAME_SIZE) {
//				System.out.println("notifyGrab");
				videoGrab.notifyGrab();
			}
			// Logger.info(tag, "视频队列剩余 " + videoList.size());
			// 单位 秒
			long timestamp = wrapper.frame.timestamp / 1000000;
			VideoDurationUpdate.getInstance().updatePlayedDuration(timestamp);
			return wrapper;
		}

	}

	/**
	 * <pre>
	 * 		音频的话 先检查一下 videoList中的第一条记录的时间戳 
	 *  	返回该时间戳时间相同 或者在该时间戳时间之前的第一帧 
	 *  	该时间戳之前的第二帧以及更早的音频时间 全部抛弃
	 * </pre>
	 * 
	 * @return
	 */
	public FrameWrapper readNextAudio() {
		FrameAudioGrabberThread audioGrab = FrameAudioGrabberThread.getInstance();
		if (audioList.isEmpty()) {
			if (audioGrab.isGrabEnd() == false) {
				audioGrab.notifyGrab();
			}
			return null;
		}
		// 音频里最少保持2帧数据
//		if (audioList.size() < 2) {
//			audioGrab.notifyGrab();
//			return null;
//		}
		else {
			synchronized (audioList) {
				FrameWrapper frameWrapper = audioList.get(0);
				audioList.remove(0);
				return frameWrapper;
			}
		}
	}

	/**
	 * 计算即将播放的最新一帧音视频时间戳差 一般情况 视频都比音频快
	 * 
	 * @return 等于0 认为时间同步 <br>
	 *         大于0 视频播放快 <br>
	 *         小于0 音频播放快 <br>
	 */
	public long getVideoSubAudioTimestampDiff() {
		// 视频队列已经消耗没了，说明视频播放快了
		if (videoList.isEmpty() && audioList.size() > 0) {
			return 1;
		}
		// 认为二者同步
		if (videoList.isEmpty() && audioList.isEmpty()) {
			return 0;
		}
		// 视频播放的慢了
		if (videoList.size() > 0 && audioList.isEmpty()) {
			return -1;
		}

		FrameWrapper videoWrapper = videoList.get(0);
		FrameWrapper audioWrapper = audioList.get(0);
		long diff = videoWrapper.frame.timestamp - audioWrapper.frame.timestamp;
//		if(diff > 44000) {
//			diff = 44000;
//		}
		Logger.info(tag, "音视频同步, 时间差(视频 - 音频) ==> " + diff);
		return diff;
	}

	public synchronized void clearAll() {
		this.videoList.clear();
		this.audioList.clear();
	}

}
